🎖️GitЯра🎖️
Node / meshtastic / Meshtastic-Android / files / feature / firmware / src / jvmMain / kotlin / org / meshtastic / feature / firmware / JvmFirmwareFileHandler.kt
Displaying Raw • Download
feature/firmware/src/jvmMain/kotlin/org/meshtastic/feature/firmware/JvmFirmwareFileHandler.kt 01cd54907d62cd90913d3d071b6bc240cae365ef (01cd5490) Text, 11.04 KB
T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.feature.firmware
Tff7b72import T7ee787co.touchlab.kermit.Logger
Tff7b72import T7ee787io.ktor.client.HttpClient
Tff7b72import T7ee787io.ktor.client.request.get
Tff7b72import T7ee787io.ktor.client.request.head
Tff7b72import T7ee787io.ktor.client.statement.bodyAsChannel
Tff7b72import T7ee787io.ktor.client.statement.bodyAsText
Tff7b72import T7ee787io.ktor.http.contentLength
Tff7b72import T7ee787io.ktor.http.isSuccess
Tff7b72import T7ee787io.ktor.utils.io.jvm.javaio.toInputStream
Tff7b72import T7ee787kotlinx.coroutines.CancellationException
Tff7b72import T7ee787kotlinx.coroutines.isActive
Tff7b72import T7ee787kotlinx.coroutines.withContext
Tff7b72import T7ee787org.koin.core.annotation.Single
Tff7b72import T7ee787org.meshtastic.core.common.util.CommonUri
Tff7b72import T7ee787org.meshtastic.core.common.util.ioDispatcher
Tff7b72import T7ee787org.meshtastic.core.model.DeviceHardware
Tff7b72import T7ee787java.io.File
Tff7b72import T7ee787java.io.FileOutputStream
Tff7b72import T7ee787java.io.IOException
Tff7b72import T7ee787java.net.URI
Tff7b72import T7ee787java.nio.file.Files
Tff7b72import T7ee787java.nio.file.StandardCopyOption
Tff7b72import T7ee787java.util.zip.ZipEntry
Tff7b72import T7ee787java.util.zip.ZipInputStream
Tff7b72private Tff7b72const Tff7b72val Te6edf3DOWNLOAD_BUFFER_SIZE Tff7b72= T79c0ff8T79c0ff1T79c0ff9T79c0ff2
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffTooManyFunctionsTa5d6ff"Tb4b4b4)
Tf0883e@Single
Tff7b72class T56d364JvmFirmwareFileHandlerTb4b4b4(Tff7b72private Tff7b72val Te6edf3clientTb4b4b4: Te6edf3HttpClientTb4b4b4) Tb4b4b4: Te6edf3FirmwareFileHandler Tb4b4b4{
Tff7b72private Tff7b72val Te6edf3tempDir Tff7b72= Te6edf3FileTb4b4b4(Te6edf3SystemTb4b4b4.Te6edf3getPropertyTb4b4b4(Ta5d6ff"Ta5d6ffjava.io.tmpdirTa5d6ff"Tb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffmeshtastic/firmware_updateTa5d6ff"Tb4b4b4)
Tff7b72override Tff7b72fun Td2a8ffcleanupAllTemporaryFilesTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3runCatching Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3tempDirTb4b4b4.Te6edf3existsTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3tempDirTb4b4b4.Te6edf3deleteRecursivelyTb4b4b4(Tb4b4b4)
Tb4b4b4}
Te6edf3tempDirTb4b4b4.Te6edf3mkdirsTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4.Te6edf3onFailure Tb4b4b4{ Te6edf3e Tff7b72-Tff7b72> Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffFailed to cleanup temp directoryTa5d6ff" Tb4b4b4} Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffcheckUrlExistsTb4b4b4(Te6edf3urlTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72= Te6edf3withContextTb4b4b4(Te6edf3ioDispatcherTb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{
Te6edf3clientTb4b4b4.Te6edf3headTb4b4b4(Te6edf3urlTb4b4b4)Tb4b4b4.Te6edf3statusTb4b4b4.Te6edf3isSuccessTb4b4b4(Tb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffTooGenericExceptionCaughtTa5d6ff"Tb4b4b4) Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffFailed to check URL existence: Tffd700$Te6edf3urlTa5d6ff" Tb4b4b4}
Tff7b72false
Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72suspend Tff7b72fun Td2a8fffetchTextTb4b4b4(Te6edf3urlTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Tffa657String? Tff7b72= Te6edf3withContextTb4b4b4(Te6edf3ioDispatcherTb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{
Tff7b72val Te6edf3response Tff7b72= Te6edf3clientTb4b4b4.Te6edf3getTb4b4b4(Te6edf3urlTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3responseTb4b4b4.Te6edf3statusTb4b4b4.Te6edf3isSuccessTb4b4b4(Tb4b4b4)Tb4b4b4) Te6edf3responseTb4b4b4.Te6edf3bodyAsTextTb4b4b4(Tb4b4b4) Tff7b72else Tff7b72null
Tb4b4b4} Tff7b72catch Tb4b4b4(Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffTooGenericExceptionCaughtTa5d6ff"Tb4b4b4) Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffFailed to fetch text from: Tffd700$Te6edf3urlTa5d6ff" Tb4b4b4}
Tff7b72null
Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffdownloadFileTb4b4b4(Te6edf3urlTb4b4b4: Tffa657StringTb4b4b4, Te6edf3fileNameTb4b4b4: Tffa657StringTb4b4b4, Te6edf3onProgressTb4b4b4: Tb4b4b4(Tffa657FloatTb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4)Tb4b4b4: Te6edf3FirmwareArtifact? Tff7b72=
Te6edf3withContextTb4b4b4(Te6edf3ioDispatcherTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3response Tff7b72=
Tff7b72try Tb4b4b4{
Te6edf3clientTb4b4b4.Te6edf3getTb4b4b4(Te6edf3urlTb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffTooGenericExceptionCaughtTa5d6ff"Tb4b4b4) Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffDownload failed for Tffd700$Te6edf3urlTa5d6ff" Tb4b4b4}
Tff7b72returnTf0883e@withContext Tff7b72null
Tb4b4b4}
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3responseTb4b4b4.Te6edf3statusTb4b4b4.Te6edf3isSuccessTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ffDownload failed: Tffd700${Te6edf3responseTb4b4b4.Te6edf3statusTb4b4b4.Te6edf3valueTffd700}Ta5d6ff for Tffd700$Te6edf3urlTa5d6ff" Tb4b4b4}
Tff7b72returnTf0883e@withContext Tff7b72null
Tb4b4b4}
Tff7b72val Te6edf3body Tff7b72= Te6edf3responseTb4b4b4.Te6edf3bodyAsChannelTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3contentLength Tff7b72= Te6edf3responseTb4b4b4.Te6edf3contentLengthTb4b4b4(Tb4b4b4) Tff7b72?: Tff7b72-T79c0ff1L
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3tempDirTb4b4b4.Te6edf3existsTb4b4b4(Tb4b4b4)Tb4b4b4) Te6edf3tempDirTb4b4b4.Te6edf3mkdirsTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3targetFile Tff7b72= Te6edf3FileTb4b4b4(Te6edf3tempDirTb4b4b4, Te6edf3fileNameTb4b4b4)
Te6edf3bodyTb4b4b4.Te6edf3toInputStreamTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3use Tb4b4b4{ Te6edf3input Tff7b72-Tff7b72>
Te6edf3FileOutputStreamTb4b4b4(Te6edf3targetFileTb4b4b4)Tb4b4b4.Te6edf3use Tb4b4b4{ Te6edf3output Tff7b72-Tff7b72>
Tff7b72val Te6edf3buffer Tff7b72= Te6edf3ByteArrayTb4b4b4(Te6edf3DOWNLOAD_BUFFER_SIZETb4b4b4)
Tff7b72var Te6edf3bytesReadTb4b4b4: Tffa657Int
Tff7b72var Te6edf3totalBytesRead Tff7b72= T79c0ff0L
Tff7b72while Tb4b4b4(Te6edf3inputTb4b4b4.Te6edf3readTb4b4b4(Te6edf3bufferTb4b4b4)Tb4b4b4.Te6edf3also Tb4b4b4{ Te6edf3bytesRead Tff7b72= Tffa657it Tb4b4b4} Tff7b72!Tff7b72= Tff7b72-T79c0ff1Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3isActiveTb4b4b4) Tff7b72throw Te6edf3CancellationExceptionTb4b4b4(Ta5d6ff"Ta5d6ffDownload cancelledTa5d6ff"Tb4b4b4)
Te6edf3outputTb4b4b4.Te6edf3writeTb4b4b4(Te6edf3bufferTb4b4b4, T79c0ff0Tb4b4b4, Te6edf3bytesReadTb4b4b4)
Te6edf3totalBytesRead Tff7b72+Tff7b72= Te6edf3bytesRead
Tff7b72if Tb4b4b4(Te6edf3contentLength Tff7b72> T79c0ff0Tb4b4b4) Tb4b4b4{
Te6edf3onProgressTb4b4b4(Te6edf3totalBytesReadTb4b4b4.Te6edf3toFloatTb4b4b4(Tb4b4b4) Tff7b72/ Te6edf3contentLengthTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3contentLength Tff7b72!Tff7b72= Tff7b72-T79c0ff1L Tff7b72&Tff7b72& Te6edf3totalBytesRead Tff7b72!Tff7b72= Te6edf3contentLengthTb4b4b4) Tb4b4b4{
Tff7b72throw Te6edf3IOExceptionTb4b4b4(Ta5d6ff"Ta5d6ffIncomplete download: expected Tffd700$Te6edf3contentLengthTa5d6ff bytes, got Tffd700$Te6edf3totalBytesReadTa5d6ff"Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Te6edf3targetFileTb4b4b4.Te6edf3toFirmwareArtifactTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffextractFirmwareTb4b4b4(
Te6edf3uriTb4b4b4: Te6edf3CommonUriTb4b4b4,
Te6edf3hardwareTb4b4b4: Te6edf3DeviceHardwareTb4b4b4,
Te6edf3fileExtensionTb4b4b4: Tffa657StringTb4b4b4,
Te6edf3preferredFilenameTb4b4b4: Tffa657String?Tb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3FirmwareArtifact? Tff7b72= Te6edf3withContextTb4b4b4(Te6edf3ioDispatcherTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3inputFile Tff7b72= Te6edf3uriTb4b4b4.Te6edf3toLocalFileOrNullTb4b4b4(Tb4b4b4) Tff7b72?: Tff7b72returnTf0883e@withContext Tff7b72null
Te6edf3extractFromZipFileTb4b4b4(Te6edf3inputFileTb4b4b4, Te6edf3hardwareTb4b4b4, Te6edf3fileExtensionTb4b4b4, Te6edf3preferredFilenameTb4b4b4)
Tb4b4b4}
Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffextractFirmwareFromZipTb4b4b4(
Te6edf3zipFileTb4b4b4: Te6edf3FirmwareArtifactTb4b4b4,
Te6edf3hardwareTb4b4b4: Te6edf3DeviceHardwareTb4b4b4,
Te6edf3fileExtensionTb4b4b4: Tffa657StringTb4b4b4,
Te6edf3preferredFilenameTb4b4b4: Tffa657String?Tb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3FirmwareArtifact? Tff7b72= Te6edf3withContextTb4b4b4(Te6edf3ioDispatcherTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3inputFile Tff7b72= Te6edf3zipFileTb4b4b4.Te6edf3toLocalFileOrNullTb4b4b4(Tb4b4b4) Tff7b72?: Tff7b72returnTf0883e@withContext Tff7b72null
Te6edf3extractFromZipFileTb4b4b4(Te6edf3inputFileTb4b4b4, Te6edf3hardwareTb4b4b4, Te6edf3fileExtensionTb4b4b4, Te6edf3preferredFilenameTb4b4b4)
Tb4b4b4}
Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffgetFileSizeTb4b4b4(Te6edf3fileTb4b4b4: Te6edf3FirmwareArtifactTb4b4b4)Tb4b4b4: Tffa657Long Tff7b72=
Te6edf3withContextTb4b4b4(Te6edf3ioDispatcherTb4b4b4) Tb4b4b4{ Te6edf3fileTb4b4b4.Te6edf3toLocalFileOrNullTb4b4b4(Tb4b4b4)Tff7b72?.Te6edf3takeIf Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3existsTb4b4b4(Tb4b4b4) Tb4b4b4}Tff7b72?.Te6edf3lengthTb4b4b4(Tb4b4b4) Tff7b72?: T79c0ff0L Tb4b4b4}
Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffdeleteFileTb4b4b4(Te6edf3fileTb4b4b4: Te6edf3FirmwareArtifactTb4b4b4) Tff7b72= Te6edf3withContextTb4b4b4(Te6edf3ioDispatcherTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3fileTb4b4b4.Te6edf3isTemporaryTb4b4b4) Tff7b72returnTf0883e@withContext
Tff7b72val Te6edf3localFile Tff7b72= Te6edf3fileTb4b4b4.Te6edf3toLocalFileOrNullTb4b4b4(Tb4b4b4) Tff7b72?: Tff7b72returnTf0883e@withContext
Tff7b72if Tb4b4b4(Te6edf3localFileTb4b4b4.Te6edf3existsTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3localFileTb4b4b4.Te6edf3deleteTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffreadBytesTb4b4b4(Te6edf3artifactTb4b4b4: Te6edf3FirmwareArtifactTb4b4b4)Tb4b4b4: Te6edf3ByteArray Tff7b72= Te6edf3withContextTb4b4b4(Te6edf3ioDispatcherTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3file Tff7b72=
Te6edf3artifactTb4b4b4.Te6edf3toLocalFileOrNullTb4b4b4(Tb4b4b4) Tff7b72?: Tff7b72throw Te6edf3IOExceptionTb4b4b4(Ta5d6ff"Ta5d6ffCannot resolve artifact to file: Tffd700${Te6edf3artifactTb4b4b4.Te6edf3uriTffd700}Ta5d6ff"Tb4b4b4)
Te6edf3fileTb4b4b4.Te6edf3readBytesTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffimportFromUriTb4b4b4(Te6edf3uriTb4b4b4: Te6edf3CommonUriTb4b4b4)Tb4b4b4: Te6edf3FirmwareArtifact? Tff7b72= Te6edf3withContextTb4b4b4(Te6edf3ioDispatcherTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3sourceFile Tff7b72= Te6edf3uriTb4b4b4.Te6edf3toLocalFileOrNullTb4b4b4(Tb4b4b4) Tff7b72?: Tff7b72returnTf0883e@withContext Tff7b72null
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3sourceFileTb4b4b4.Te6edf3existsTb4b4b4(Tb4b4b4)Tb4b4b4) Tff7b72returnTf0883e@withContext Tff7b72null
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3tempDirTb4b4b4.Te6edf3existsTb4b4b4(Tb4b4b4)Tb4b4b4) Te6edf3tempDirTb4b4b4.Te6edf3mkdirsTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3dest Tff7b72= Te6edf3FileTb4b4b4(Te6edf3tempDirTb4b4b4, Ta5d6ff"Ta5d6ffota_firmware.binTa5d6ff"Tb4b4b4)
Te6edf3sourceFileTb4b4b4.Te6edf3copyToTb4b4b4(Te6edf3destTb4b4b4, Te6edf3overwrite Tff7b72= Tff7b72trueTb4b4b4)
Te6edf3destTb4b4b4.Te6edf3toFirmwareArtifactTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffgetDisplayNameTb4b4b4(Te6edf3uriTb4b4b4: Te6edf3CommonUriTb4b4b4)Tb4b4b4: Tffa657String? Tff7b72= Te6edf3withContextTb4b4b4(Te6edf3ioDispatcherTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3localFile Tff7b72= Te6edf3uriTb4b4b4.Te6edf3toLocalFileOrNullTb4b4b4(Tb4b4b4)
Te6edf3localFileTff7b72?.Te6edf3nameTff7b72?.Te6edf3takeIf Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3isNotBlankTb4b4b4(Tb4b4b4) Tb4b4b4}
Tff7b72?: Te6edf3run Tb4b4b4{
Tff7b72val Te6edf3scheme Tff7b72= Te6edf3runCatching Tb4b4b4{ Te6edf3URITb4b4b4(Te6edf3uriTb4b4b4.Te6edf3toStringTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4.Te6edf3scheme Tb4b4b4}Tb4b4b4.Te6edf3getOrNullTb4b4b4(Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3scheme Tff7b72=Tff7b72= Ta5d6ff"Ta5d6fffileTa5d6ff"Tb4b4b4) Tb4b4b4{
Te6edf3uriTb4b4b4.Te6edf3pathSegmentsTb4b4b4.Te6edf3lastOrNullTb4b4b4(Tb4b4b4)Tff7b72?.Te6edf3takeIf Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3isNotBlankTb4b4b4(Tb4b4b4) Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72null
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
T8b949e/**
* Fully expands [artifact] into memory, keyed by entry name.
*
* Shares [extractZipEntriesBounded] with the Android handler so the two cannot drift — they previously carried
* independent copies of this loop, and only one of them got bounded.
*/
Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffextractZipEntriesTb4b4b4(Te6edf3artifactTb4b4b4: Te6edf3FirmwareArtifactTb4b4b4)Tb4b4b4: Te6edf3MapTff7b72<Tffa657StringTb4b4b4, Te6edf3ByteArrayTff7b72> Tff7b72=
Te6edf3withContextTb4b4b4(Te6edf3ioDispatcherTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3file Tff7b72= Te6edf3artifactTb4b4b4.Te6edf3toLocalFileOrNullTb4b4b4(Tb4b4b4) Tff7b72?: Tff7b72throw Te6edf3IOExceptionTb4b4b4(Ta5d6ff"Ta5d6ffCannot resolve artifact: Tffd700${Te6edf3artifactTb4b4b4.Te6edf3uriTffd700}Ta5d6ff"Tb4b4b4)
Te6edf3requireTb4b4b4(Te6edf3fileTb4b4b4.Te6edf3lengthTb4b4b4(Tb4b4b4) Tff7b72<Tff7b72= Te6edf3MAX_FIRMWARE_ZIP_BYTESTb4b4b4) Tb4b4b4{
Ta5d6ff"Ta5d6ffFirmware archive is Tffd700${Te6edf3fileTb4b4b4.Te6edf3lengthTb4b4b4(Tb4b4b4)Tffd700}Ta5d6ff bytes, over the Tffd700$Te6edf3MAX_FIRMWARE_ZIP_BYTESTa5d6ff limitTa5d6ff"
Tb4b4b4}
Te6edf3fileTb4b4b4.Te6edf3inputStreamTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3use Tb4b4b4{ Te6edf3extractZipEntriesBoundedTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffcopyToUriTb4b4b4(Te6edf3sourceTb4b4b4: Te6edf3FirmwareArtifactTb4b4b4, Te6edf3destinationUriTb4b4b4: Te6edf3CommonUriTb4b4b4)Tb4b4b4: Tffa657Long Tff7b72=
Te6edf3withContextTb4b4b4(Te6edf3ioDispatcherTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3sourceFile Tff7b72= Te6edf3sourceTb4b4b4.Te6edf3toLocalFileOrNullTb4b4b4(Tb4b4b4) Tff7b72?: Tff7b72throw Te6edf3IOExceptionTb4b4b4(Ta5d6ff"Ta5d6ffCannot open source URITa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3destinationFile Tff7b72= Te6edf3destinationUriTb4b4b4.Te6edf3toLocalFileOrNullTb4b4b4(Tb4b4b4) Tff7b72?: Tff7b72throw Te6edf3IOExceptionTb4b4b4(Ta5d6ff"Ta5d6ffCannot open destination URITa5d6ff"Tb4b4b4)
Te6edf3destinationFileTb4b4b4.Te6edf3parentFileTff7b72?.Te6edf3mkdirsTb4b4b4(Tb4b4b4)
Te6edf3FilesTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3sourceFileTb4b4b4.Te6edf3toPathTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3destinationFileTb4b4b4.Te6edf3toPathTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3StandardCopyOptionTb4b4b4.Te6edf3REPLACE_EXISTINGTb4b4b4)
Te6edf3destinationFileTb4b4b4.Te6edf3lengthTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffNestedBlockDepthTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffReturnCountTa5d6ff"Tb4b4b4)
Tff7b72private Tff7b72fun Td2a8ffextractFromZipFileTb4b4b4(
Te6edf3zipFileTb4b4b4: Te6edf3FileTb4b4b4,
Te6edf3hardwareTb4b4b4: Te6edf3DeviceHardwareTb4b4b4,
Te6edf3fileExtensionTb4b4b4: Tffa657StringTb4b4b4,
Te6edf3preferredFilenameTb4b4b4: Tffa657String?Tb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3FirmwareArtifact? Tb4b4b4{
Tff7b72val Te6edf3target Tff7b72= Te6edf3hardwareTb4b4b4.Te6edf3effectiveTarget
Tff7b72if Tb4b4b4(Te6edf3targetTb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72& Te6edf3preferredFilename Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tff7b72return Tff7b72null
Tff7b72val Te6edf3targetLowerCase Tff7b72= Te6edf3targetTb4b4b4.Te6edf3lowercaseTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3preferredFilenameLower Tff7b72= Te6edf3preferredFilenameTff7b72?.Te6edf3lowercaseTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3matchingEntries Tff7b72= Te6edf3mutableListOfTff7b72<Te6edf3PairTff7b72<Te6edf3ZipEntryTb4b4b4, Te6edf3FileTff7b72>Tff7b72>Tb4b4b4(Tb4b4b4)
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3tempDirTb4b4b4.Te6edf3existsTb4b4b4(Tb4b4b4)Tb4b4b4) Te6edf3tempDirTb4b4b4.Te6edf3mkdirsTb4b4b4(Tb4b4b4)
Te6edf3ZipInputStreamTb4b4b4(Te6edf3zipFileTb4b4b4.Te6edf3inputStreamTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4.Te6edf3use Tb4b4b4{ Te6edf3zipInput Tff7b72-Tff7b72>
Tff7b72var Te6edf3entry Tff7b72= Te6edf3zipInputTb4b4b4.Te6edf3nextEntry
Tff7b72while Tb4b4b4(Te6edf3entry Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3name Tff7b72= Te6edf3entryTb4b4b4.Te6edf3nameTb4b4b4.Te6edf3lowercaseTb4b4b4(Tb4b4b4)
T8b949e// File(name).name strips directory components, mitigating ZipSlip attacks
Tff7b72val Te6edf3entryFileName Tff7b72= Te6edf3FileTb4b4b4(Te6edf3nameTb4b4b4)Tb4b4b4.Te6edf3name
Tff7b72val Te6edf3isMatch Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3preferredFilenameLower Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3entryFileName Tff7b72=Tff7b72= Te6edf3preferredFilenameLower
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72!Te6edf3entryTb4b4b4.Te6edf3isDirectory Tff7b72&Tff7b72& Te6edf3isValidFirmwareFileTb4b4b4(Te6edf3nameTb4b4b4, Te6edf3targetLowerCaseTb4b4b4, Te6edf3fileExtensionTb4b4b4)
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3isMatchTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3outFile Tff7b72= Te6edf3FileTb4b4b4(Te6edf3tempDirTb4b4b4, Te6edf3entryFileNameTb4b4b4)
Te6edf3FileOutputStreamTb4b4b4(Te6edf3outFileTb4b4b4)Tb4b4b4.Te6edf3use Tb4b4b4{ Te6edf3output Tff7b72-Tff7b72> Te6edf3zipInputTb4b4b4.Te6edf3copyToTb4b4b4(Te6edf3outputTb4b4b4) Tb4b4b4}
Te6edf3matchingEntriesTb4b4b4.Te6edf3addTb4b4b4(Te6edf3entry Te6edf3to Te6edf3outFileTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3preferredFilenameLower Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Tff7b72return Te6edf3outFileTb4b4b4.Te6edf3toFirmwareArtifactTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Te6edf3entry Tff7b72= Te6edf3zipInputTb4b4b4.Te6edf3nextEntry
Tb4b4b4}
Tb4b4b4}
Tff7b72return Te6edf3matchingEntriesTb4b4b4.Te6edf3minByOrNull Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3firstTb4b4b4.Te6edf3nameTb4b4b4.Te6edf3length Tb4b4b4}Tff7b72?.Te6edf3secondTff7b72?.Te6edf3toFirmwareArtifactTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffisValidFirmwareFileTb4b4b4(Te6edf3filenameTb4b4b4: Tffa657StringTb4b4b4, Te6edf3targetTb4b4b4: Tffa657StringTb4b4b4, Te6edf3fileExtensionTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72=
Te6edf3orgTb4b4b4.Te6edf3meshtasticTb4b4b4.Te6edf3featureTb4b4b4.Te6edf3firmwareTb4b4b4.Te6edf3isValidFirmwareFileTb4b4b4(Te6edf3filenameTb4b4b4, Te6edf3targetTb4b4b4, Te6edf3fileExtensionTb4b4b4)
Tff7b72private Tff7b72fun Te6edf3FileTb4b4b4.Td2a8fftoFirmwareArtifactTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3FirmwareArtifact Tff7b72=
Te6edf3FirmwareArtifactTb4b4b4(Te6edf3uri Tff7b72= Te6edf3CommonUriTb4b4b4.Te6edf3parseTb4b4b4(Te6edf3toURITb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3toStringTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4, Te6edf3fileName Tff7b72= Te6edf3nameTb4b4b4, Te6edf3isTemporary Tff7b72= Tff7b72trueTb4b4b4)
Tff7b72private Tff7b72fun Te6edf3FirmwareArtifactTb4b4b4.Td2a8fftoLocalFileOrNullTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3File? Tff7b72= Te6edf3uriTb4b4b4.Te6edf3toLocalFileOrNullTb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72fun Te6edf3CommonUriTb4b4b4.Td2a8fftoLocalFileOrNullTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3File? Tff7b72= Te6edf3runCatching Tb4b4b4{
Tff7b72val Te6edf3parsedUri Tff7b72= Te6edf3URITb4b4b4(Te6edf3toStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3parsedUriTb4b4b4.Te6edf3scheme Tff7b72=Tff7b72= Ta5d6ff"Ta5d6fffileTa5d6ff"Tb4b4b4) Te6edf3FileTb4b4b4(Te6edf3parsedUriTb4b4b4) Tff7b72else Tff7b72null
Tb4b4b4}
Tb4b4b4.Te6edf3getOrNullTb4b4b4(Tb4b4b4)
Tb4b4b4}
Served by rngit 1.5.0 - Generated in 0.1s